package fieldmaps.files;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;

import fieldmaps.types.MapInfo;


public class BilFormatParser {
	
	private MapInfo mapInfo;
	private Map<String, String> properties = new HashMap<String, String>();

	private int [][] data;
	private boolean mapLoaded;

	public void exportMap(String filename) throws IOException {
		loadMap(filename);
		this.exportData(filename + ".txt");
	}

	public void loadMap (String filename) throws IOException {
		this.readHeader(filename + ".hdr");
		this.readData(filename + ".bil");
		this.mapLoaded = true;
	}
	
	public int[][] getMatrixData (String filename) throws IOException {
		if (!this.mapLoaded) {
			loadMap(filename);
		}
		return this.data;
	}
	
	public int[][] getMatrixData () throws IllegalArgumentException {
		if (!this.mapLoaded) {
			throw new IllegalArgumentException("Map's not loaded!");
		}
		return this.data;
	}

	public MapInfo getMapInfo() {
		return this.mapInfo;
	}
	
	public Map<String, String> getHeader () {
		return this.properties;
	}
	
	private void readHeader (String filename) throws IOException {
		
		FileInputStream file = new FileInputStream(filename);
		InputStreamReader stream = new InputStreamReader(file);
		BufferedReader reader = new BufferedReader(stream);
		String line = null;

		while ((line = reader.readLine()) != null) {
			String[] values = line.split(" +");
			if(values.length > 1) {
				properties.put(values[0], values[1]);
			}
		}

		System.out.println("Parsing the Header...");

		this.mapInfo.setByteOrder (properties.get("BYTEORDER").charAt(0));
		this.mapInfo.setLayout (properties.get("LAYOUT"));
		this.mapInfo.setNrows (Integer.valueOf(properties.get("NROWS")));
		this.mapInfo.setNcols (Integer.valueOf(properties.get("NCOLS")));
		this.mapInfo.setNbands (Integer.valueOf(properties.get("NBANDS")));
		this.mapInfo.setNbits (Integer.valueOf(properties.get("NBITS")));
		this.mapInfo.setBandrowbytes (Integer.valueOf(properties.get("BANDROWBYTES")));
		this.mapInfo.setTotalrowbytes (Integer.valueOf(properties.get("TOTALROWBYTES")));
		this.mapInfo.setBandgapbytes (Integer.valueOf(properties.get("BANDGAPBYTES")));
		this.mapInfo.setNodata (Integer.valueOf(properties.get("NODATA")));
		this.mapInfo.setUlxmap (Double.valueOf(properties.get("ULXMAP")));
		this.mapInfo.setUlymap (Double.valueOf(properties.get("ULYMAP")));
		this.mapInfo.setXdim (Double.valueOf(properties.get("XDIM")));
		this.mapInfo.setYdim (Double.valueOf(properties.get("YDIM")));

	}

	private void readData (String filename) throws IOException {

		char byteOrder = mapInfo.getByteOrder();
		int nbits = mapInfo.getNbits();
		int nrows = mapInfo.getNrows();
		int ncols = mapInfo.getNcols();

		if (byteOrder != 'I') {
			throw new IOException("The data must be represented little endian.");
		}

		int cantbytes = nbits/8;
		byte[] auxvalue = new byte[cantbytes];
		data = new int[nrows][ncols];

		FileInputStream datafile = new FileInputStream(filename);

		System.out.println("Reading the data from file...");

		for (int i = 0; i < nrows; i++) {
			for (int j = 0; j < ncols; j++) {
				int value = 0;
				if (datafile.read(auxvalue) != cantbytes) {
					throw new IOException("Error while reading the data file.");
				}
				for (int k = 0; k < auxvalue.length; k++) {
					value <<= k * 8;
					value += auxvalue[k];
				}
				data[i][j] = value;
			}
		}

		System.out.println("---> The file was readed ok!");
		System.out.println("");
	}

	private void exportData (String filename) throws IOException {

		int nrows = mapInfo.getNrows();
		int ncols = mapInfo.getNcols();

		FileOutputStream result = new FileOutputStream(filename);
		OutputStreamWriter outputstream = new OutputStreamWriter(result);
		BufferedWriter writer = new BufferedWriter(outputstream);

		System.out.println ("Exporting data...");
		System.out.println ("--->Output file:" + filename);

		for (int i = 0; i < nrows; i++) {
			for (int j = 0; j < ncols; j++) {
				writer.append(String.valueOf(data[i][j]));
				writer.append(" ");
			}
			writer.newLine();
		}

		writer.flush();
		writer.close();
		outputstream.close();
		result.close();

		System.out.println("--->The data was exported!");
		System.out.println("");
	}

}
